﻿Imports System.Runtime.InteropServices
Imports System.Management

Public Class clsSound

    Private Declare Function fncNumOfActiveSession Lib "VuMeter.dll" () As Integer
    Private Declare Function fncCurrentActivePeak Lib "VuMeter.dll" () As Double

    Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer

    'Playsound function is the api call to play the wave file sounds.
    'HandleModule is only used when you want to play a embedded sound in
    'your .exe file. Must use the SND_Resource flag. The PS_Flags
    'parameter is for specifiying special functionality for the waveform
    'sound.
    '
    Private Declare Function playSound Lib "winmm.dll" Alias "PlaySoundA" (ByVal sndToPlay As String, ByVal handleModule As Integer, ByVal PS_Flags As Integer) As Integer
    '
    'Will return how many sound cards are available on the computer.
    'You can use this function to check a users computer to make sure
    'they have a sound card installed on their computer.
    Private Declare Function waveOutGetNumDevs Lib "winmm.dll" () As Integer
    '    'The below constants are for use with the PS_Flags parameter in the     'PlaySound function above.    '    'PS = PlaySound, abbreviated    '    'Look for application specific association    Private Const PS_APPLICATION = &H80    '    'Name is a WIN.INI [sounds] entry    Private Const PS_ALIAS = &H10000    '    'Name is a WIN.INI [sounds] entry identifier    Private Const PS_ALIAS_ID = &H110000    '    'Play asynchronously    Private Const PS_ASYNC = &H1    '    'Name is a file name    Private Const PS_FILENAME = &H20000    '    'Loop the sound until PlaySound is called again, you can loop the     'sound on if you play the sound "ASync" you can NOT play the sound     'in loop mode while playing the sound in "Sync".    Private Const PS_LOOP = &H8    '    'sndToPlay points to a memory file    Private Const PS_MEMORY = &H4    '    'Silence not default, if sound not found    Private Const PS_NODEFAULT = &H2    '    'Don't stop any currently playing sound    Private Const PS_NOSTOP = &H10    '    'Don't wait if the driver is busy    Private Const PS_NOWAIT = &H2000    '    'Purge non-static events for task    Private Const PS_PURGE = &H40    '    'Name is a resource name or atom    Private Const PS_RESOURCE = &H40004    '    'Play synchronously (default), you usually do not have to specify    'this flag if you want the sound to play synchronously.    Private Const PS_SYNC = &H0

    Public Structure stDeviceInfo
        Dim strDevName As String
        Dim strDevID As String
    End Structure

    'Will hold the path to the filename
    Private mstrFileName As String = Nothing
    Private mcstrPlayAlias As String = "BgSound"

    Public ReadOnly Property IsSoundCardInstalled() As Boolean
        Get

            Dim intNumDevices As Integer

            'Get how many sound card devices are currently installed on 
            'the users system.
            '
            intNumDevices = waveOutGetNumDevs()

            'If the API call above returned a value higher than 0 then 
            'the current computer system does have a sound card 
            'installed.
            '
            'I decided to have this property return yes or no instead
            'of true or false. I am not sure but I just like the yes/no
            'better than saying true/false.
            '
            If intNumDevices > 0 Then
                Return True
            Else
                Return False
            End If
        End Get
    End Property

    Public ReadOnly Property GetNumberOfSoundCards() As Integer

        Get
            Dim intNumDevices As Integer

            'Returns how many sound card devices are installed on the 
            'current System.
            intNumDevices = waveOutGetNumDevs

            Return intNumDevices

        End Get

    End Property

    Public ReadOnly Property GetAllDevices() As List(Of stDeviceInfo)

        Get
            Dim lstDevices As List(Of stDeviceInfo) = New List(Of stDeviceInfo)

            Try
                Dim stDev As stDeviceInfo

                Dim objSearcher As New System.Management.ManagementObjectSearcher("SELECT * FROM Win32_SoundDevice")

                Dim objCollection As System.Management.ManagementObjectCollection = objSearcher.Get()

                For Each obj As System.Management.ManagementObject In objCollection

                    stDev = New stDeviceInfo()
                    stDev.strDevID = obj.GetPropertyValue("DeviceId").ToString()
                    stDev.strDevName = obj.GetPropertyValue("Caption").ToString()
                    lstDevices.Add(stDev)

                Next

            Catch ex As Exception
            End Try

            Return lstDevices

        End Get

    End Property

    Public Property SoundPath() As String

        Get
            'This is the path to the wave sound file to play.
            'This will make sure the path is not null before it goes 
            'any futher.
            If mstrFileName = "" Or Nothing Then
                Return "No path been selected"
            Else
                Return mstrFileName
            End If

        End Get

        Set(ByVal Value As String)
            mstrFileName = Value
        End Set

    End Property

    Public Sub New()

    End Sub

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    Public Function fncPlay(strPath As String) As Boolean
        fncPlay = False
        Try
            'open file 
            mciSendString("Open " & Chr(34) & strPath & Chr(34) & " alias " & mcstrPlayAlias, CStr(0), 0, 0)

            'play it
            mciSendString("play " & mcstrPlayAlias & " repeat", CStr(0), 0, 0)
            'mciSendString("play " & mcstrPlayAlias, CStr(0), 0, 0)

            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

    Public Function fncStop() As Boolean
        fncStop = False
        Try
            'stop playing 
            mciSendString("stop " & mcstrPlayAlias, CStr(0), 0, 0)

            ''Pauses the sound
            'mciSendString("pause " & mcstrPlayAlias, CStr(0), 0, 0)

            ''Resumes the paused sound
            'mciSendString("resume " & mcstrPlayAlias, CStr(0), 0, 0)

            'Close the sound, this is the opposite to Open and will make so 
            'you can't use the sound any more'unless you open it again of course.
            mciSendString("close " & mcstrPlayAlias, CStr(0), 0, 0)

            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

    Public Function fncNumActiveSession() As Integer

        fncNumActiveSession = 0

        Try
            Return fncNumOfActiveSession()
        Catch ex As Exception
            Return 0
        End Try
    End Function


    Public Function fncCurActivePeak() As Double

        fncCurActivePeak = 0.0F

        Try
            Return fncCurrentActivePeak()
        Catch ex As Exception
            Return 0.0F
        End Try
    End Function


    'Public Function fncPlaySoundFile(ByVal loopPlaying As Boolean, ByVal aSync As Boolean) As Boolean

    '    fncPlaySoundFile = False

    '    Try
    '        'If you play the sound in "Sync" then the file will be opened
    '        'and played in the same thread and then your app will not yet
    '        'get control back until the file is finished playing. load and 
    '        'play another sound until the current sound is finished.
    '        'If you Then play the sound with the "ASync" flag then the sound 
    '        'will be opened and played in its own thread and will not
    '        '
    '        'So if you want to be able to continue to have control within
    '        'your application then you will want to play the sound using the
    '        '"ASync" flag. Because if you play the sound in "Sync" then your
    '        'application will NOT respond.
    '        '
    '        ''Playing in "Sync" mode is the default flag
    '        '
    '        If loopPlaying And aSync Then

    '            'Will open and play the sound in Async mode while looping
    '            'the sound.
    '            '
    '            'You must play the sound "ASync" for you to be able to loop     '            'the sound.    '            '
    '            'You can NOT loop the sound while playing in playing in 
    '            '"Sync" mode.
    '            '
    '            playSound(mstrFileName, 0, PS_LOOP Or PS_ASYNC Or PS_FILENAME)

    '        ElseIf aSync And Not loopPlaying Then

    '            'Play the sound in "ASync" mode with OUT looping since the 
    '            'user selected True in the ASync parameter and false in the
    '            'loopPlay parameter. 
    '            '
    '            'In ASync mode the sound will be opened and played in its 
    '            'Own thread, so your app will Respond even while the sound
    '            'is playing.
    '            '
    '            playSound(mstrFileName, 0, PS_ASYNC Or PS_FILENAME)


    '        Else

    '            'Play the sound in "Sync" since the user selected False in
    '            'the ASync parameter.
    '            '
    '            'Remember, you can NOT Loop the sound while playing in Sync
    '            'mode.
    '            '
    '            'You will not be able to do anything with your application
    '            'until the sound has finished playing. Your app will Not
    '            'respond while the sound is currently playing in "Sync" mode.
    '            '
    '            playSound(mstrFileName, 0, PS_FILENAME Or PS_SYNC)

    '        End If

    '        Return True

    '    Catch ex As Exception
    '        Return False
    '    End Try

    'End Function

    'Public Function fncPlaySystemSound(ByVal systemSoundName As String, ByVal aSync As Boolean, ByVal loopPlaying As Boolean) As Boolean

    '    fncPlaySystemSound = False
    '    Try

    '        'Will play specific system sounds based on the SoundName. You
    '        'can find and customize the system sounds in the registry. You
    '        'can also get the systemsound names under the Sounds and Audio
    '        'devices under the Control Panel.
    '        '
    '        'Play the system sound in either Sync or ASynce mode, depending
    '        'on what mode was selected. Also to Loop play or not.
    '        '
    '        'Read the comments in the above playSoundFile sub for more 
    '        'indepth explanation of the playing options below.
    '        '
    '        If loopPlaying And aSync Then

    '            playSound(systemSoundName, 0, PS_ASYNC Or PS_ALIAS Or PS_LOOP)

    '        ElseIf aSync And Not loopPlaying Then

    '            playSound(systemSoundName, 0, PS_ASYNC Or PS_ALIAS)

    '        Else

    '            playSound(systemSoundName, 0, PS_ALIAS Or PS_SYNC)

    '        End If

    '        Return True
    '    Catch ex As Exception
    '        Return False
    '    End Try

    'End Function

    'Public Function fncStopPlay() As Boolean

    '    fncStopPlay = False

    '    Try
    '        'This will cause the soundPlayer to stop playing the sound file
    '        'that was currently playing.
    '        '
    '        playSound(Nothing, Nothing, Nothing)

    '        Return True

    '    Catch ex As Exception
    '        Return False
    '    End Try

    'End Function

#Region "Reference"
    'http://www.codeproject.com/Articles/18685/Enumerating-Sound-Recording-Devices-Using-winmm-dl
    'http://forum.codecall.net/topic/51741-playing-sounds-in-vbnet/
    'http://social.msdn.microsoft.com/Forums/vstudio/de-DE/c3d6692f-acad-4f21-b5d9-f553001949cf/is-it-possible-to-detect-if-an-audio-device-is-connected-to-the-computer
#End Region

End Class
